﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace WWWSiteHelper
{
    public enum StackOperating
    {
        Nothing,
        Put,
        ReturnAndClear,
        ReturnClearAndPut
    }

    public class StackBehaviorProvider<T>
    {
        private readonly ISet<T> affectingStates;
        public StackBehaviorProvider(ISet<T> affectingStates)
        {
            this.affectingStates = affectingStates;
        }
        public StackOperating DefaultBehavior(T prevState, T state)
        {
            if (!prevState.Equals(state) && affectingStates.Contains(prevState))
            {
                if (affectingStates.Contains(state))
                {
                    return StackOperating.ReturnClearAndPut;
                }
                else
                {
                    return StackOperating.ReturnAndClear;
                }
            }
            else if (affectingStates.Contains(state))
            {
                return StackOperating.Put;
            }
            return StackOperating.Nothing;
        }
    }

    public class AutomatonWithStack<T>
    {
        private T startState;
        private ICollection<T> acceptingStates;
        private TransitionFunction transition;
        private GiveBack giveBack;
        private StackBehavior behavior;

        public delegate void GiveBack(T prevState, T state, String token);
        public delegate T TransitionFunction(T state, char symbol);
        public delegate StackOperating StackBehavior(T prevState, T state);

        public AutomatonWithStack(T startState, ICollection<T> acceptingStates, TransitionFunction transition, GiveBack giveBack, StackBehavior behavior)
        {
            this.startState = startState;
            this.acceptingStates = acceptingStates;
            this.transition = transition;
            this.giveBack = giveBack;
            this.behavior = behavior;
        }

        public bool Execute(string content)
        {
            StringBuilder bob = new StringBuilder();
            T state = startState;
            foreach (char symbol in content)
            {
                T newState = transition(state, symbol);
                StackOperating behavior = this.behavior(state, newState);
                //System.Console.WriteLine("prevstate: " + state + " newstate: " + newState);
                if (behavior == StackOperating.ReturnAndClear)
                {
                    //System.Console.WriteLine("behavior: ReturnAndClear");
                    giveBack(state, newState, bob.ToString());
                    bob.Clear();
                }
                else if (behavior == StackOperating.Put)
                {
                    //System.Console.WriteLine("behavior: Put");
                    bob.Append(symbol);
                }
                else if (behavior == StackOperating.ReturnClearAndPut)
                {
                    //System.Console.WriteLine("behavior: ReturnClearAndPut");
                    giveBack(state, newState, bob.ToString());
                    bob.Clear();
                    bob.Append(symbol);
                }
                //System.Console.WriteLine("behavior: other");
                state = newState;
            }
            foreach (T acceptingState in acceptingStates)
            {
                if (acceptingState.Equals(state))
                {
                    return true;
                }
            }
            return false;
        }
    }
}
